gtkwindow: Make sure to update the shadow width, opaque region and border windows...
authorJasper St. Pierre <jstpierre@mecheye.net>
Wed, 17 Sep 2014 22:16:45 +0000 (16:16 -0600)
committerJasper St. Pierre <jstpierre@mecheye.net>
Fri, 19 Sep 2014 23:39:46 +0000 (17:39 -0600)
Otherwise, they might not be properly set before the window is mapped.

For the opaque region and border window, it means that they won't get
set before the next size allocation, which tends to not be a bit deal.

For the shadow width, though, _GTK_FRAME_EXTENTS has a different meaning
when it's set before the window is mapped, so we need to make sure that
it's properly set when the window is mapped.

gtk/gtkwindow.c

index 5145b7427e3ba42c62e3b1a9e85f934e98587724..4a686374ec46f3af55a88a934cc1dcd223e8cb08 100644 (file)
@@ -6248,830 +6248,857 @@ check_scale_changed (GtkWindow *window)
 }
 
 static void
-gtk_window_realize (GtkWidget *widget)
+sum_borders (GtkBorder *one,
+             GtkBorder *two)
 {
-  GtkAllocation allocation;
-  GtkWindow *window;
-  GdkWindow *parent_window;
-  GdkWindow *gdk_window;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  GtkWindowPrivate *priv;
+  one->top += two->top;
+  one->right += two->right;
+  one->bottom += two->bottom;
+  one->left += two->left;
+}
+
+static void
+max_borders (GtkBorder *one,
+             GtkBorder *two)
+{
+  one->top = MAX (one->top, two->top);
+  one->right = MAX (one->right, two->right);
+  one->bottom = MAX (one->bottom, two->bottom);
+  one->left = MAX (one->left, two->left);
+}
+
+static void
+subtract_borders (GtkBorder *one,
+                  GtkBorder *two)
+{
+  one->top -= two->top;
+  one->right -= two->right;
+  one->bottom -= two->bottom;
+  one->left -= two->left;
+}
+
+static void
+add_window_frame_style_class (GtkStyleContext *context)
+{
+  gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
+  gtk_style_context_add_class (context, "window-frame");
+}
+
+static void
+get_shadow_width (GtkWidget *widget,
+                  GtkBorder *shadow_width)
+{
+  GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+  GtkBorder border = { 0 };
+  GtkBorder d = { 0 };
+  GtkBorder margin;
+  GtkStyleContext *context;
+  GtkStateFlags state, s;
+  GtkCssValue *shadows;
   gint i;
-  GList *link;
 
-  window = GTK_WINDOW (widget);
-  priv = window->priv;
+  *shadow_width = border;
 
-  if (!priv->client_decorated && gtk_window_should_use_csd (window))
-    create_decoration (widget);
+  if (!priv->decorated ||
+      !priv->client_decorated)
+    return;
 
-  gtk_widget_get_allocation (widget, &allocation);
+  if (priv->maximized ||
+      priv->fullscreen ||
+      priv->tiled)
+    return;
 
-  if (gtk_widget_get_parent_window (widget))
-    {
-      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-      gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
-      G_GNUC_END_IGNORE_DEPRECATIONS;
+  state = gtk_widget_get_state_flags (widget);
+  context = gtk_widget_get_style_context (widget);
 
-      attributes.x = allocation.x;
-      attributes.y = allocation.y;
-      attributes.width = allocation.width;
-      attributes.height = allocation.height;
-      attributes.window_type = GDK_WINDOW_CHILD;
+  gtk_style_context_save (context);
+  add_window_frame_style_class (context);
 
-      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+  /* We don't want windows to jump as they go to backdrop,
+   * therefore we use the maximum of the decoration sizes
+   * for focused and unfocused.
+   */
+  for (i = 0; i < 2; i++)
+    {
+      if (i == 0)
+        s = state & ~GTK_STATE_FLAG_BACKDROP;
+      else
+        s = state | GTK_STATE_FLAG_BACKDROP;
 
-      attributes.visual = gtk_widget_get_visual (widget);
-      attributes.wclass = GDK_INPUT_OUTPUT;
+      /* Always sum border + padding */
+      gtk_style_context_get_border (context, s, &border);
+      gtk_style_context_get_padding (context, s, &d);
+      sum_borders (&d, &border);
 
-      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+      /* Calculate the size of the drop shadows ... */
+      gtk_style_context_set_state (context, s);
+      shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW);
+      _gtk_css_shadows_value_get_extents (shadows, &border);
 
-      gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
-                                  &attributes, attributes_mask);
-      gtk_widget_set_window (widget, gdk_window);
-      gtk_widget_register_window (widget, gdk_window);
-      gtk_widget_set_realized (widget, TRUE);
+      if (priv->type != GTK_WINDOW_POPUP)
+        {
+          /* ... and compare it to the margin size, which we use for resize grips */
+          gtk_style_context_get_margin (context, s, &margin);
+          max_borders (&border, &margin);
+        }
 
-      return;
+      sum_borders (&d, &border);
+      max_borders (shadow_width, &d);
     }
 
-  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-  gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
-  G_GNUC_END_IGNORE_DEPRECATIONS;
+  gtk_style_context_restore (context);
+}
 
-  /* ensure widget tree is properly size allocated */
-  if (allocation.x == -1 &&
-      allocation.y == -1 &&
-      allocation.width == 1 &&
-      allocation.height == 1)
-    {
-      gint w, h;
+/* We're placing 8 input-only windows around
+ * the window content as resize handles, as
+ * follows:
+ *
+ * +-----------------------------------+
+ * | +------+-----------------+------+ |
+ * | |      |                 |      | |
+ * | |   +--+-----------------+--+   | |
+ * | |   |                       |   | |
+ * | +---+                       +---+ |
+ * | |   |                       |   | |
+ * | |   |                       |   | |
+ * | |   |                       |   | |
+ * | +---+                       +---+ |
+ * | |   |                       |   | |
+ * | |   +--+-----------------+--+   | |
+ * | |      |                 |      | |
+ * | +------+-----------------+------+ |
+ * +-----------------------------------+
+ *
+ * The corner windows are shaped to allow them
+ * to extend into the edges. If the window is
+ * not resizable in both dimensions, we hide
+ * the corner windows and the edge windows in
+ * the nonresizable dimension and make the
+ * remaining edge window extend all the way.
+ *
+ * The border are where we place the resize handles
+ * is also used to draw the window shadow, which may
+ * extend out farther than the handles (or the other
+ * way around).
+ */
+static void
+update_border_windows (GtkWindow *window)
+{
+  GtkWidget *widget = (GtkWidget *)window;
+  GtkWindowPrivate *priv = window->priv;
+  gboolean resize_h, resize_v;
+  gint handle;
+  cairo_region_t *region;
+  cairo_rectangle_int_t rect;
+  gint width, height;
+  GtkBorder border;
+  GtkBorder window_border;
+  GtkStyleContext *context;
+  GtkStateFlags state;
 
-      allocation.x = 0;
-      allocation.y = 0;
+  if (!priv->client_decorated)
+    return;
 
-      gtk_window_guess_default_size (window, &allocation.width, &allocation.height);
-      gtk_window_get_remembered_size (window, &w, &h);
-      allocation.width = MAX (allocation.width, w);
-      allocation.height = MAX (allocation.height, h);
-      if (allocation.width == 0 || allocation.height == 0)
-       {
-         /* non-empty window */
-         allocation.width = 200;
-         allocation.height = 200;
-       }
-      gtk_widget_size_allocate (widget, &allocation);
-      
-      _gtk_container_queue_resize (GTK_CONTAINER (widget));
+  state = gtk_widget_get_state_flags (widget);
+  context = gtk_widget_get_style_context (widget);
 
-      g_return_if_fail (!gtk_widget_get_realized (widget));
-    }
+  gtk_style_context_save (context);
+  add_window_frame_style_class (context);
+  gtk_style_context_set_state (context, state);
+  gtk_style_context_get_margin (context, state, &border);
+  gtk_widget_style_get (widget,
+                        "decoration-resize-handle", &handle,
+                        NULL);
+  gtk_style_context_restore (context);
+  get_shadow_width (widget, &window_border);
 
-  if (priv->hardcoded_window)
+  if (priv->border_window[0] == NULL)
+    goto shape;
+
+  if (!priv->resizable ||
+      priv->tiled ||
+      priv->fullscreen ||
+      priv->maximized)
     {
-      gdk_window = priv->hardcoded_window;
-      gtk_widget_get_allocation (widget, &allocation);
-      gdk_window_resize (gdk_window, allocation.width, allocation.height);
+      resize_h = resize_v = FALSE;
     }
   else
     {
-      switch (priv->type)
+      resize_h = resize_v = TRUE;
+      if (priv->geometry_info)
         {
-        case GTK_WINDOW_TOPLEVEL:
-          attributes.window_type = GDK_WINDOW_TOPLEVEL;
-          break;
-        case GTK_WINDOW_POPUP:
-          attributes.window_type = GDK_WINDOW_TEMP;
-          break;
-        default:
-          g_warning (G_STRLOC": Unknown window type %d!", priv->type);
-          break;
-        }
-
-#ifdef GDK_WINDOWING_WAYLAND
-      if (priv->use_subsurface &&
-          GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
-        attributes.window_type = GDK_WINDOW_SUBSURFACE;
-#endif
+          GdkGeometry *geometry = &priv->geometry_info->geometry;
+          GdkWindowHints flags = priv->geometry_info->mask;
 
-      attributes.title = priv->title;
-      attributes.wmclass_name = priv->wmclass_name;
-      attributes.wmclass_class = priv->wmclass_class;
-      attributes.wclass = GDK_INPUT_OUTPUT;
-      attributes.visual = gtk_widget_get_visual (widget);
+          if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
+            {
+              resize_h = geometry->min_width != geometry->max_width;
+              resize_v = geometry->min_height != geometry->max_height;
+            }
+        }
+    }
 
-      attributes_mask = 0;
-      parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+  width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right);
+  height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom);
 
-      gtk_widget_get_allocation (widget, &allocation);
-      attributes.width = allocation.width;
-      attributes.height = allocation.height;
-      attributes.event_mask = gtk_widget_get_events (widget);
-      attributes.event_mask |= (GDK_EXPOSURE_MASK |
-                                GDK_BUTTON_PRESS_MASK |
-                                GDK_BUTTON_RELEASE_MASK |
-                                GDK_BUTTON_MOTION_MASK |
-                                GDK_KEY_PRESS_MASK |
-                                GDK_KEY_RELEASE_MASK |
-                                GDK_ENTER_NOTIFY_MASK |
-                                GDK_LEAVE_NOTIFY_MASK |
-                                GDK_FOCUS_CHANGE_MASK |
-                                GDK_STRUCTURE_MASK);
-
-      if (priv->decorated &&
-          (priv->client_decorated || priv->custom_title))
-        attributes.event_mask |= GDK_POINTER_MOTION_MASK;
-
-      attributes.type_hint = priv->type_hint;
-
-      attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
-      attributes_mask |= (priv->title ? GDK_WA_TITLE : 0);
-      attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0);
-
-      gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
-    }
-
-  gtk_widget_set_window (widget, gdk_window);
-  gtk_widget_register_window (widget, gdk_window);
-  gtk_widget_set_realized (widget, TRUE);
-
-  /* We don't need to set a background on the GdkWindow; with decorations
-   * we draw the background ourself
-   */
-  if (!priv->client_decorated)
-    gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
+  if (resize_h && resize_v)
+    {
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
+                              window_border.left - border.left, window_border.top - border.top,
+                              border.left + handle, border.top + handle);
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
+                              window_border.left + width - handle, window_border.top - border.top,
+                              border.right + handle, border.top + handle);
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
+                              window_border.left - border.left, window_border.top + height - handle,
+                              window_border.left + handle, border.bottom + handle);
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
+                              window_border.left + width - handle, window_border.top + height - handle,
+                              border.right + handle, border.bottom + handle);
 
-  attributes.x = allocation.x;
-  attributes.y = allocation.y;
-  attributes.width = allocation.width;
-  attributes.height = allocation.height;
-  attributes.window_type = GDK_WINDOW_CHILD;
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = border.left + handle;
+      rect.height = border.top + handle;
+      region = cairo_region_create_rectangle (&rect);
+      rect.x = border.left;
+      rect.y = border.top;
+      rect.width = handle;
+      rect.height = handle;
+      cairo_region_subtract_rectangle (region, &rect);
+      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
+                                       region, 0, 0);
+      cairo_region_destroy (region);
 
-  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = border.right + handle;
+      rect.height = border.top + handle;
+      region = cairo_region_create_rectangle (&rect);
+      rect.x = 0;
+      rect.y = border.top;
+      rect.width = handle;
+      rect.height = handle;
+      cairo_region_subtract_rectangle (region, &rect);
+      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
+                                       region, 0, 0);
+      cairo_region_destroy (region);
 
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.wclass = GDK_INPUT_OUTPUT;
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = border.left + handle;
+      rect.height = border.bottom + handle;
+      region = cairo_region_create_rectangle (&rect);
+      rect.x = border.left;
+      rect.y = 0;
+      rect.width = handle;
+      rect.height = handle;
+      cairo_region_subtract_rectangle (region, &rect);
+      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
+                                       region, 0, 0);
+      cairo_region_destroy (region);
 
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = border.right + handle;
+      rect.height = border.bottom + handle;
+      region = cairo_region_create_rectangle (&rect);
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = handle;
+      rect.height = handle;
+      cairo_region_subtract_rectangle (region, &rect);
+      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
+                                       region, 0, 0);
+      cairo_region_destroy (region);
 
-  if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL)
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+    }
+  else
     {
-      GdkCursorType cursor_type[8] = {
-        GDK_TOP_LEFT_CORNER,
-        GDK_TOP_SIDE,
-        GDK_TOP_RIGHT_CORNER,
-        GDK_LEFT_SIDE,
-        GDK_RIGHT_SIDE,
-        GDK_BOTTOM_LEFT_CORNER,
-        GDK_BOTTOM_SIDE,
-        GDK_BOTTOM_RIGHT_CORNER
-      };
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+    }
 
-      attributes.wclass = GDK_INPUT_ONLY;
-      attributes.width = 1;
-      attributes.height = 1;
-      attributes.event_mask = GDK_BUTTON_PRESS_MASK;
-      attributes_mask = GDK_WA_CURSOR;
+  if (resize_v)
+    {
+      gint x, w;
 
-      for (i = 0; i < 8; i++)
+      if (resize_h)
         {
-          attributes.cursor = gdk_cursor_new (cursor_type[i]);
-          priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask);
-          g_object_unref (attributes.cursor);
-
-          gdk_window_show (priv->border_window[i]);
-          gtk_widget_register_window (widget, priv->border_window[i]);
+          x = window_border.left + handle;
+          w = width - 2 * handle;
+        }
+      else
+        {
+          x = 0;
+          w = width + window_border.left + window_border.right;
         }
-    }
 
-  if (priv->transient_parent &&
-      gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
-    gdk_window_set_transient_for (gdk_window,
-                                  gtk_widget_get_window (GTK_WIDGET (priv->transient_parent)));
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH],
+                              x, window_border.top - border.top,
+                              w, border.top);
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH],
+                              x, window_border.top + height,
+                              w, border.bottom);
 
-  if (priv->wm_role)
-    gdk_window_set_role (gdk_window, priv->wm_role);
-  
-  if (!priv->decorated || priv->client_decorated)
-    gdk_window_set_decorations (gdk_window, 0);
-  else if (priv->custom_title)
-    gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER);
-  
-  if (!priv->deletable)
-    gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
-  
-  if (gtk_window_get_skip_pager_hint (window))
-    gdk_window_set_skip_pager_hint (gdk_window, TRUE);
-  
-  if (gtk_window_get_skip_taskbar_hint (window))
-    gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
-  
-  if (gtk_window_get_accept_focus (window))
-    gdk_window_set_accept_focus (gdk_window, TRUE);
-  else
-    gdk_window_set_accept_focus (gdk_window, FALSE);
-  
-  if (gtk_window_get_focus_on_map (window))
-    gdk_window_set_focus_on_map (gdk_window, TRUE);
-  else
-    gdk_window_set_focus_on_map (gdk_window, FALSE);
-  
-  if (priv->modal)
-    gdk_window_set_modal_hint (gdk_window, TRUE);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
+    }
   else
-    gdk_window_set_modal_hint (gdk_window, FALSE);
-
-  if (priv->startup_id)
     {
-#ifdef GDK_WINDOWING_X11
-      if (GDK_IS_X11_WINDOW (gdk_window))
-        {
-          guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
-          if (timestamp != GDK_CURRENT_TIME)
-            gdk_x11_window_set_user_time (gdk_window, timestamp);
-        }
-#endif
-      if (!startup_id_is_fake (priv->startup_id))
-        gdk_window_set_startup_id (gdk_window, priv->startup_id);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
     }
 
-#ifdef GDK_WINDOWING_X11
-  if (priv->initial_timestamp != GDK_CURRENT_TIME)
+  if (resize_h)
     {
-      if (GDK_IS_X11_WINDOW (gdk_window))
-        gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp);
-    }
-#endif
+      gint y, h;
 
-  if (priv->application)
-    gtk_application_handle_window_realize (priv->application, window);
+      if (resize_v)
+        {
+          y = window_border.top + handle;
+          h = height - 2 * handle;
+        }
+      else
+        {
+          y = 0;
+          h = height + window_border.top + window_border.bottom;
+        }
 
-  /* Icons */
-  gtk_window_realize_icon (window);
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST],
+                              window_border.left - border.left, y,
+                              border.left, h);
 
-  link = priv->popovers;
+      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST],
+                              window_border.left + width, y,
+                              border.right, h);
 
-  while (link)
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]);
+      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+    }
+  else
     {
-      GtkWindowPopover *popover = link->data;
-      link = link->next;
-      popover_realize (popover->widget, popover, window);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]);
+      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]);
     }
 
-  check_scale_changed (window);
-}
+shape:
+  /* we also update the input shape, which makes it so that clicks
+   * outside the border windows go through
+   */
 
-static void
-popover_unrealize (GtkWidget        *widget,
-                   GtkWindowPopover *popover,
-                   GtkWindow        *window)
-{
-  gtk_widget_unregister_window (GTK_WIDGET (window), popover->window);
-  gtk_widget_unrealize (popover->widget);
-  gdk_window_destroy (popover->window);
-  popover->window = NULL;
+  if (priv->type != GTK_WINDOW_POPUP)
+    subtract_borders (&window_border, &border);
+
+  rect.x = window_border.left;
+  rect.y = window_border.top;
+  rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right;
+  rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom;
+  region = cairo_region_create_rectangle (&rect);
+  gtk_widget_input_shape_combine_region (widget, region);
+  cairo_region_destroy (region);
 }
 
 static void
-gtk_window_unrealize (GtkWidget *widget)
+update_shadow_width (GtkWindow *window,
+                     GtkBorder *border)
 {
-  GtkWindow *window = GTK_WINDOW (widget);
-  GtkWindowPrivate *priv = window->priv;
-  GtkWindowGeometryInfo *info;
-  GList *link;
-  gint i;
-
-  /* On unrealize, we reset the size of the window such
-   * that we will re-apply the default sizing stuff
-   * next time we show the window.
-   *
-   * Default positioning is reset on unmap, instead of unrealize.
-   */
-  priv->need_default_size = TRUE;
-  info = gtk_window_get_geometry_info (window, FALSE);
-  if (info)
-    {
-      info->resize_width = -1;
-      info->resize_height = -1;
-      info->last.configure_request.x = 0;
-      info->last.configure_request.y = 0;
-      info->last.configure_request.width = -1;
-      info->last.configure_request.height = -1;
-      /* be sure we reset geom hints on re-realize */
-      info->last.flags = 0;
-    }
-
-  if (priv->popup_menu)
-    {
-      gtk_widget_destroy (priv->popup_menu);
-      priv->popup_menu = NULL;
-    }
-
-  /* Icons */
-  gtk_window_unrealize_icon (window);
-
-  if (priv->border_window[0] != NULL)
-    {
-      for (i = 0; i < 8; i++)
-        {
-          gtk_widget_unregister_window (widget, priv->border_window[i]);
-          gdk_window_destroy (priv->border_window[i]);
-          priv->border_window[i] = NULL;
-        }
-    }
-
-  link = priv->popovers;
-
-  while (link)
-    {
-      GtkWindowPopover *popover = link->data;
-      link = link->next;
-      popover_unrealize (popover->widget, popover, window);
-    }
+  GdkWindow *gdk_window;
 
-  GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
+  gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
 
-  priv->hardcoded_window = NULL;
+  if (gdk_window)
+    gdk_window_set_shadow_width (gdk_window,
+                                 border->left,
+                                 border->right,
+                                 border->top,
+                                 border->bottom);
 }
 
 static void
-sum_borders (GtkBorder *one,
-             GtkBorder *two)
+corner_rect (cairo_rectangle_int_t *rect,
+             const GtkCssValue     *value)
 {
-  one->top += two->top;
-  one->right += two->right;
-  one->bottom += two->bottom;
-  one->left += two->left;
+  rect->width = _gtk_css_corner_value_get_x (value, 100);
+  rect->height = _gtk_css_corner_value_get_y (value, 100);
 }
 
 static void
-max_borders (GtkBorder *one,
-             GtkBorder *two)
+subtract_corners_from_region (cairo_region_t        *region,
+                              cairo_rectangle_int_t *extents,
+                              GtkStyleContext       *context)
 {
-  one->top = MAX (one->top, two->top);
-  one->right = MAX (one->right, two->right);
-  one->bottom = MAX (one->bottom, two->bottom);
-  one->left = MAX (one->left, two->left);
-}
+  cairo_rectangle_int_t rect;
 
-static void
-subtract_borders (GtkBorder *one,
-                  GtkBorder *two)
-{
-  one->top -= two->top;
-  one->right -= two->right;
-  one->bottom -= two->bottom;
-  one->left -= two->left;
+  gtk_style_context_save (context);
+  add_window_frame_style_class (context);
+
+  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS));
+  rect.x = extents->x;
+  rect.y = extents->y;
+  cairo_region_subtract_rectangle (region, &rect);
+
+  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS));
+  rect.x = extents->x + extents->width - rect.width;
+  rect.y = extents->y;
+  cairo_region_subtract_rectangle (region, &rect);
+
+  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS));
+  rect.x = extents->x;
+  rect.y = extents->y + extents->height - rect.height;
+  cairo_region_subtract_rectangle (region, &rect);
+
+  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS));
+  rect.x = extents->x + extents->width - rect.width;
+  rect.y = extents->y + extents->height - rect.height;
+  cairo_region_subtract_rectangle (region, &rect);
+
+  gtk_style_context_restore (context);
 }
 
 static void
-add_window_frame_style_class (GtkStyleContext *context)
+update_opaque_region (GtkWindow           *window,
+                      GtkBorder           *border,
+                      const GtkAllocation *allocation)
 {
-  gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
-  gtk_style_context_add_class (context, "window-frame");
+  GtkWidget *widget = GTK_WIDGET (window);
+  cairo_region_t *opaque_region;
+  GtkStyleContext *context;
+  gboolean is_opaque = FALSE;
+
+  if (!gtk_widget_get_realized (widget))
+      return;
+
+  context = gtk_widget_get_style_context (widget);
+
+  if (!gtk_widget_get_app_paintable (widget))
+    {
+      const GdkRGBA *color;
+      color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
+      is_opaque = (color->alpha >= 1.0);
+    }
+
+  if (is_opaque)
+    {
+      cairo_rectangle_int_t rect;
+
+      rect.x = border->left;
+      rect.y = border->top;
+      rect.width = allocation->width - border->left - border->right;
+      rect.height = allocation->height - border->top - border->bottom;
+
+      opaque_region = cairo_region_create_rectangle (&rect);
+
+      subtract_corners_from_region (opaque_region, &rect, context);
+    }
+  else
+    {
+      opaque_region = NULL;
+    }
+
+  gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region);
+
+  cairo_region_destroy (opaque_region);
 }
 
 static void
-update_window_style_classes (GtkWindow *window)
+update_realized_window_properties (GtkWindow     *window,
+                                   GtkAllocation *child_allocation,
+                                   GtkBorder     *window_border)
 {
   GtkWindowPrivate *priv = window->priv;
-  GtkStyleContext *context;
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (window));
+  if (priv->client_decorated)
+    update_shadow_width (window, window_border);
 
-  if (priv->tiled)
-    gtk_style_context_add_class (context, "tiled");
-  else
-    gtk_style_context_remove_class (context, "tiled");
+  update_opaque_region (window, window_border, child_allocation);
 
-  if (priv->maximized)
-    gtk_style_context_add_class (context, "maximized");
-  else
-    gtk_style_context_remove_class (context, "maximized");
+  if (gtk_widget_is_toplevel (GTK_WIDGET (window)))
+    update_border_windows (window);
 }
 
 static void
-get_shadow_width (GtkWidget *widget,
-                  GtkBorder *shadow_width)
+gtk_window_realize (GtkWidget *widget)
 {
-  GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
-  GtkBorder border = { 0 };
-  GtkBorder d = { 0 };
-  GtkBorder margin;
-  GtkStyleContext *context;
-  GtkStateFlags state, s;
-  GtkCssValue *shadows;
+  GtkAllocation allocation;
+  GtkAllocation child_allocation;
+  GtkWindow *window;
+  GdkWindow *parent_window;
+  GdkWindow *gdk_window;
+  GdkWindowAttr attributes;
+  GtkBorder window_border;
+  gint attributes_mask;
+  GtkWindowPrivate *priv;
   gint i;
+  GList *link;
 
-  *shadow_width = border;
+  window = GTK_WINDOW (widget);
+  priv = window->priv;
 
-  if (!priv->decorated ||
-      !priv->client_decorated)
-    return;
+  if (!priv->client_decorated && gtk_window_should_use_csd (window))
+    create_decoration (widget);
 
-  if (priv->maximized ||
-      priv->fullscreen ||
-      priv->tiled)
-    return;
+  gtk_widget_get_allocation (widget, &allocation);
 
-  state = gtk_widget_get_state_flags (widget);
-  context = gtk_widget_get_style_context (widget);
+  if (gtk_widget_get_parent_window (widget))
+    {
+      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+      gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
+      G_GNUC_END_IGNORE_DEPRECATIONS;
 
-  gtk_style_context_save (context);
-  add_window_frame_style_class (context);
+      attributes.x = allocation.x;
+      attributes.y = allocation.y;
+      attributes.width = allocation.width;
+      attributes.height = allocation.height;
+      attributes.window_type = GDK_WINDOW_CHILD;
 
-  /* We don't want windows to jump as they go to backdrop,
-   * therefore we use the maximum of the decoration sizes
-   * for focused and unfocused.
-   */
-  for (i = 0; i < 2; i++)
-    {
-      if (i == 0)
-        s = state & ~GTK_STATE_FLAG_BACKDROP;
-      else
-        s = state | GTK_STATE_FLAG_BACKDROP;
+      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
 
-      /* Always sum border + padding */
-      gtk_style_context_get_border (context, s, &border);
-      gtk_style_context_get_padding (context, s, &d);
-      sum_borders (&d, &border);
+      attributes.visual = gtk_widget_get_visual (widget);
+      attributes.wclass = GDK_INPUT_OUTPUT;
 
-      /* Calculate the size of the drop shadows ... */
-      gtk_style_context_set_state (context, s);
-      shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW);
-      _gtk_css_shadows_value_get_extents (shadows, &border);
+      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
 
-      if (priv->type != GTK_WINDOW_POPUP)
-        {
-          /* ... and compare it to the margin size, which we use for resize grips */
-          gtk_style_context_get_margin (context, s, &margin);
-          max_borders (&border, &margin);
-        }
+      gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                                  &attributes, attributes_mask);
+      gtk_widget_set_window (widget, gdk_window);
+      gtk_widget_register_window (widget, gdk_window);
+      gtk_widget_set_realized (widget, TRUE);
 
-      sum_borders (&d, &border);
-      max_borders (shadow_width, &d);
+      return;
     }
 
-  gtk_style_context_restore (context);
-}
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+  gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
+  G_GNUC_END_IGNORE_DEPRECATIONS;
 
-/* We're placing 8 input-only windows around
- * the window content as resize handles, as
- * follows:
- *
- * +-----------------------------------+
- * | +------+-----------------+------+ |
- * | |      |                 |      | |
- * | |   +--+-----------------+--+   | |
- * | |   |                       |   | |
- * | +---+                       +---+ |
- * | |   |                       |   | |
- * | |   |                       |   | |
- * | |   |                       |   | |
- * | +---+                       +---+ |
- * | |   |                       |   | |
- * | |   +--+-----------------+--+   | |
- * | |      |                 |      | |
- * | +------+-----------------+------+ |
- * +-----------------------------------+
- *
- * The corner windows are shaped to allow them
- * to extend into the edges. If the window is
- * not resizable in both dimensions, we hide
- * the corner windows and the edge windows in
- * the nonresizable dimension and make the
- * remaining edge window extend all the way.
- *
- * The border are where we place the resize handles
- * is also used to draw the window shadow, which may
- * extend out farther than the handles (or the other
- * way around).
- */
-static void
-update_border_windows (GtkWindow *window)
-{
-  GtkWidget *widget = (GtkWidget *)window;
-  GtkWindowPrivate *priv = window->priv;
-  gboolean resize_h, resize_v;
-  gint handle;
-  cairo_region_t *region;
-  cairo_rectangle_int_t rect;
-  gint width, height;
-  GtkBorder border;
-  GtkBorder window_border;
-  GtkStyleContext *context;
-  GtkStateFlags state;
+  /* ensure widget tree is properly size allocated */
+  if (allocation.x == -1 &&
+      allocation.y == -1 &&
+      allocation.width == 1 &&
+      allocation.height == 1)
+    {
+      gint w, h;
 
-  if (!priv->client_decorated)
-    return;
+      allocation.x = 0;
+      allocation.y = 0;
 
-  state = gtk_widget_get_state_flags (widget);
-  context = gtk_widget_get_style_context (widget);
+      gtk_window_guess_default_size (window, &allocation.width, &allocation.height);
+      gtk_window_get_remembered_size (window, &w, &h);
+      allocation.width = MAX (allocation.width, w);
+      allocation.height = MAX (allocation.height, h);
+      if (allocation.width == 0 || allocation.height == 0)
+       {
+         /* non-empty window */
+         allocation.width = 200;
+         allocation.height = 200;
+       }
+      gtk_widget_size_allocate (widget, &allocation);
 
-  gtk_style_context_save (context);
-  add_window_frame_style_class (context);
-  gtk_style_context_set_state (context, state);
-  gtk_style_context_get_margin (context, state, &border);
-  gtk_widget_style_get (widget,
-                        "decoration-resize-handle", &handle,
-                        NULL);
-  gtk_style_context_restore (context);
-  get_shadow_width (widget, &window_border);
+      _gtk_container_queue_resize (GTK_CONTAINER (widget));
 
-  if (priv->border_window[0] == NULL)
-    goto shape;
+      g_return_if_fail (!gtk_widget_get_realized (widget));
+    }
 
-  if (!priv->resizable ||
-      priv->tiled ||
-      priv->fullscreen ||
-      priv->maximized)
+  if (priv->hardcoded_window)
     {
-      resize_h = resize_v = FALSE;
+      gdk_window = priv->hardcoded_window;
+      gtk_widget_get_allocation (widget, &allocation);
+      gdk_window_resize (gdk_window, allocation.width, allocation.height);
     }
   else
     {
-      resize_h = resize_v = TRUE;
-      if (priv->geometry_info)
+      switch (priv->type)
         {
-          GdkGeometry *geometry = &priv->geometry_info->geometry;
-          GdkWindowHints flags = priv->geometry_info->mask;
-
-          if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
-            {
-              resize_h = geometry->min_width != geometry->max_width;
-              resize_v = geometry->min_height != geometry->max_height;
-            }
+        case GTK_WINDOW_TOPLEVEL:
+          attributes.window_type = GDK_WINDOW_TOPLEVEL;
+          break;
+        case GTK_WINDOW_POPUP:
+          attributes.window_type = GDK_WINDOW_TEMP;
+          break;
+        default:
+          g_warning (G_STRLOC": Unknown window type %d!", priv->type);
+          break;
         }
-    }
 
-  width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right);
-  height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom);
+#ifdef GDK_WINDOWING_WAYLAND
+      if (priv->use_subsurface &&
+          GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
+        attributes.window_type = GDK_WINDOW_SUBSURFACE;
+#endif
 
-  if (resize_h && resize_v)
-    {
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
-                              window_border.left - border.left, window_border.top - border.top,
-                              border.left + handle, border.top + handle);
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
-                              window_border.left + width - handle, window_border.top - border.top,
-                              border.right + handle, border.top + handle);
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
-                              window_border.left - border.left, window_border.top + height - handle,
-                              window_border.left + handle, border.bottom + handle);
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
-                              window_border.left + width - handle, window_border.top + height - handle,
-                              border.right + handle, border.bottom + handle);
+      attributes.title = priv->title;
+      attributes.wmclass_name = priv->wmclass_name;
+      attributes.wmclass_class = priv->wmclass_class;
+      attributes.wclass = GDK_INPUT_OUTPUT;
+      attributes.visual = gtk_widget_get_visual (widget);
 
-      rect.x = 0;
-      rect.y = 0;
-      rect.width = border.left + handle;
-      rect.height = border.top + handle;
-      region = cairo_region_create_rectangle (&rect);
-      rect.x = border.left;
-      rect.y = border.top;
-      rect.width = handle;
-      rect.height = handle;
-      cairo_region_subtract_rectangle (region, &rect);
-      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
-                                       region, 0, 0);
-      cairo_region_destroy (region);
+      attributes_mask = 0;
+      parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
 
-      rect.x = 0;
-      rect.y = 0;
-      rect.width = border.right + handle;
-      rect.height = border.top + handle;
-      region = cairo_region_create_rectangle (&rect);
-      rect.x = 0;
-      rect.y = border.top;
-      rect.width = handle;
-      rect.height = handle;
-      cairo_region_subtract_rectangle (region, &rect);
-      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
-                                       region, 0, 0);
-      cairo_region_destroy (region);
+      gtk_widget_get_allocation (widget, &allocation);
+      attributes.width = allocation.width;
+      attributes.height = allocation.height;
+      attributes.event_mask = gtk_widget_get_events (widget);
+      attributes.event_mask |= (GDK_EXPOSURE_MASK |
+                                GDK_BUTTON_PRESS_MASK |
+                                GDK_BUTTON_RELEASE_MASK |
+                                GDK_BUTTON_MOTION_MASK |
+                                GDK_KEY_PRESS_MASK |
+                                GDK_KEY_RELEASE_MASK |
+                                GDK_ENTER_NOTIFY_MASK |
+                                GDK_LEAVE_NOTIFY_MASK |
+                                GDK_FOCUS_CHANGE_MASK |
+                                GDK_STRUCTURE_MASK);
 
-      rect.x = 0;
-      rect.y = 0;
-      rect.width = border.left + handle;
-      rect.height = border.bottom + handle;
-      region = cairo_region_create_rectangle (&rect);
-      rect.x = border.left;
-      rect.y = 0;
-      rect.width = handle;
-      rect.height = handle;
-      cairo_region_subtract_rectangle (region, &rect);
-      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
-                                       region, 0, 0);
-      cairo_region_destroy (region);
+      if (priv->decorated &&
+          (priv->client_decorated || priv->custom_title))
+        attributes.event_mask |= GDK_POINTER_MOTION_MASK;
 
-      rect.x = 0;
-      rect.y = 0;
-      rect.width = border.right + handle;
-      rect.height = border.bottom + handle;
-      region = cairo_region_create_rectangle (&rect);
-      rect.x = 0;
-      rect.y = 0;
-      rect.width = handle;
-      rect.height = handle;
-      cairo_region_subtract_rectangle (region, &rect);
-      gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
-                                       region, 0, 0);
-      cairo_region_destroy (region);
+      attributes.type_hint = priv->type_hint;
 
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
-    }
-  else
-    {
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+      attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
+      attributes_mask |= (priv->title ? GDK_WA_TITLE : 0);
+      attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0);
+
+      gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
     }
 
-  if (resize_v)
+  gtk_widget_set_window (widget, gdk_window);
+  gtk_widget_register_window (widget, gdk_window);
+  gtk_widget_set_realized (widget, TRUE);
+
+  /* We don't need to set a background on the GdkWindow; with decorations
+   * we draw the background ourself
+   */
+  if (!priv->client_decorated)
+    gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
+
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.wclass = GDK_INPUT_OUTPUT;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+  if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL)
     {
-      gint x, w;
+      GdkCursorType cursor_type[8] = {
+        GDK_TOP_LEFT_CORNER,
+        GDK_TOP_SIDE,
+        GDK_TOP_RIGHT_CORNER,
+        GDK_LEFT_SIDE,
+        GDK_RIGHT_SIDE,
+        GDK_BOTTOM_LEFT_CORNER,
+        GDK_BOTTOM_SIDE,
+        GDK_BOTTOM_RIGHT_CORNER
+      };
 
-      if (resize_h)
-        {
-          x = window_border.left + handle;
-          w = width - 2 * handle;
-        }
-      else
+      attributes.wclass = GDK_INPUT_ONLY;
+      attributes.width = 1;
+      attributes.height = 1;
+      attributes.event_mask = GDK_BUTTON_PRESS_MASK;
+      attributes_mask = GDK_WA_CURSOR;
+
+      for (i = 0; i < 8; i++)
         {
-          x = 0;
-          w = width + window_border.left + window_border.right;
+          attributes.cursor = gdk_cursor_new (cursor_type[i]);
+          priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask);
+          g_object_unref (attributes.cursor);
+
+          gdk_window_show (priv->border_window[i]);
+          gtk_widget_register_window (widget, priv->border_window[i]);
         }
+    }
+
+  if (priv->transient_parent &&
+      gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
+    gdk_window_set_transient_for (gdk_window,
+                                  gtk_widget_get_window (GTK_WIDGET (priv->transient_parent)));
+
+  if (priv->wm_role)
+    gdk_window_set_role (gdk_window, priv->wm_role);
+
+  if (!priv->decorated || priv->client_decorated)
+    gdk_window_set_decorations (gdk_window, 0);
+  else if (priv->custom_title)
+    gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER);
+
+  if (!priv->deletable)
+    gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
+
+  if (gtk_window_get_skip_pager_hint (window))
+    gdk_window_set_skip_pager_hint (gdk_window, TRUE);
+
+  if (gtk_window_get_skip_taskbar_hint (window))
+    gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
 
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH],
-                              x, window_border.top - border.top,
-                              w, border.top);
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH],
-                              x, window_border.top + height,
-                              w, border.bottom);
+  if (gtk_window_get_accept_focus (window))
+    gdk_window_set_accept_focus (gdk_window, TRUE);
+  else
+    gdk_window_set_accept_focus (gdk_window, FALSE);
 
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
-    }
+  if (gtk_window_get_focus_on_map (window))
+    gdk_window_set_focus_on_map (gdk_window, TRUE);
   else
-    {
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
-    }
+    gdk_window_set_focus_on_map (gdk_window, FALSE);
 
-  if (resize_h)
-    {
-      gint y, h;
+  if (priv->modal)
+    gdk_window_set_modal_hint (gdk_window, TRUE);
+  else
+    gdk_window_set_modal_hint (gdk_window, FALSE);
 
-      if (resize_v)
-        {
-          y = window_border.top + handle;
-          h = height - 2 * handle;
-        }
-      else
+  if (priv->startup_id)
+    {
+#ifdef GDK_WINDOWING_X11
+      if (GDK_IS_X11_WINDOW (gdk_window))
         {
-          y = 0;
-          h = height + window_border.top + window_border.bottom;
+          guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+          if (timestamp != GDK_CURRENT_TIME)
+            gdk_x11_window_set_user_time (gdk_window, timestamp);
         }
-
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST],
-                              window_border.left - border.left, y,
-                              border.left, h);
-
-      gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST],
-                              window_border.left + width, y,
-                              border.right, h);
-
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]);
-      gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+#endif
+      if (!startup_id_is_fake (priv->startup_id))
+        gdk_window_set_startup_id (gdk_window, priv->startup_id);
     }
-  else
+
+#ifdef GDK_WINDOWING_X11
+  if (priv->initial_timestamp != GDK_CURRENT_TIME)
     {
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]);
-      gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+      if (GDK_IS_X11_WINDOW (gdk_window))
+        gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp);
     }
+#endif
 
-shape:
-  /* we also update the input shape, which makes it so that clicks
-   * outside the border windows go through
-   */
+  child_allocation.x = 0;
+  child_allocation.y = 0;
+  child_allocation.width = allocation.width;
+  child_allocation.height = allocation.height;
 
-  if (priv->type != GTK_WINDOW_POPUP)
-    subtract_borders (&window_border, &border);
+  get_shadow_width (widget, &window_border);
 
-  rect.x = window_border.left;
-  rect.y = window_border.top;
-  rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right;
-  rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom;
-  region = cairo_region_create_rectangle (&rect);
-  gtk_widget_input_shape_combine_region (widget, region);
-  cairo_region_destroy (region);
-}
+  update_realized_window_properties (window, &child_allocation, &window_border);
 
-static void
-update_shadow_width (GtkWindow *window,
-                     GtkBorder *border)
-{
-  GdkWindow *gdk_window;
+  if (priv->application)
+    gtk_application_handle_window_realize (priv->application, window);
 
-  gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+  /* Icons */
+  gtk_window_realize_icon (window);
 
-  if (gdk_window)
-    gdk_window_set_shadow_width (gdk_window,
-                                 border->left,
-                                 border->right,
-                                 border->top,
-                                 border->bottom);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_realize (popover->widget, popover, window);
+    }
+
+  check_scale_changed (window);
 }
 
 static void
-corner_rect (cairo_rectangle_int_t *rect,
-             const GtkCssValue     *value)
+popover_unrealize (GtkWidget        *widget,
+                   GtkWindowPopover *popover,
+                   GtkWindow        *window)
 {
-  rect->width = _gtk_css_corner_value_get_x (value, 100);
-  rect->height = _gtk_css_corner_value_get_y (value, 100);
+  gtk_widget_unregister_window (GTK_WIDGET (window), popover->window);
+  gtk_widget_unrealize (popover->widget);
+  gdk_window_destroy (popover->window);
+  popover->window = NULL;
 }
 
 static void
-subtract_corners_from_region (cairo_region_t        *region,
-                              cairo_rectangle_int_t *extents,
-                              GtkStyleContext       *context)
+gtk_window_unrealize (GtkWidget *widget)
 {
-  cairo_rectangle_int_t rect;
+  GtkWindow *window = GTK_WINDOW (widget);
+  GtkWindowPrivate *priv = window->priv;
+  GtkWindowGeometryInfo *info;
+  GList *link;
+  gint i;
 
-  gtk_style_context_save (context);
-  add_window_frame_style_class (context);
+  /* On unrealize, we reset the size of the window such
+   * that we will re-apply the default sizing stuff
+   * next time we show the window.
+   *
+   * Default positioning is reset on unmap, instead of unrealize.
+   */
+  priv->need_default_size = TRUE;
+  info = gtk_window_get_geometry_info (window, FALSE);
+  if (info)
+    {
+      info->resize_width = -1;
+      info->resize_height = -1;
+      info->last.configure_request.x = 0;
+      info->last.configure_request.y = 0;
+      info->last.configure_request.width = -1;
+      info->last.configure_request.height = -1;
+      /* be sure we reset geom hints on re-realize */
+      info->last.flags = 0;
+    }
 
-  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS));
-  rect.x = extents->x;
-  rect.y = extents->y;
-  cairo_region_subtract_rectangle (region, &rect);
+  if (priv->popup_menu)
+    {
+      gtk_widget_destroy (priv->popup_menu);
+      priv->popup_menu = NULL;
+    }
 
-  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS));
-  rect.x = extents->x + extents->width - rect.width;
-  rect.y = extents->y;
-  cairo_region_subtract_rectangle (region, &rect);
+  /* Icons */
+  gtk_window_unrealize_icon (window);
 
-  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS));
-  rect.x = extents->x;
-  rect.y = extents->y + extents->height - rect.height;
-  cairo_region_subtract_rectangle (region, &rect);
+  if (priv->border_window[0] != NULL)
+    {
+      for (i = 0; i < 8; i++)
+        {
+          gtk_widget_unregister_window (widget, priv->border_window[i]);
+          gdk_window_destroy (priv->border_window[i]);
+          priv->border_window[i] = NULL;
+        }
+    }
 
-  corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS));
-  rect.x = extents->x + extents->width - rect.width;
-  rect.y = extents->y + extents->height - rect.height;
-  cairo_region_subtract_rectangle (region, &rect);
+  link = priv->popovers;
 
-  gtk_style_context_restore (context);
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_unrealize (popover->widget, popover, window);
+    }
+
+  GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
+
+  priv->hardcoded_window = NULL;
 }
 
 static void
-update_opaque_region (GtkWindow           *window,
-                      GtkBorder           *border,
-                      const GtkAllocation *allocation)
+update_window_style_classes (GtkWindow *window)
 {
-  GtkWidget *widget = GTK_WIDGET (window);
-  cairo_region_t *opaque_region;
+  GtkWindowPrivate *priv = window->priv;
   GtkStyleContext *context;
-  gboolean is_opaque = FALSE;
-
-  if (!gtk_widget_get_realized (widget))
-      return;
-
-  context = gtk_widget_get_style_context (widget);
-
-  if (!gtk_widget_get_app_paintable (widget))
-    {
-      const GdkRGBA *color;
-      color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
-      is_opaque = (color->alpha >= 1.0);
-    }
-
-  if (is_opaque)
-    {
-      cairo_rectangle_int_t rect;
-
-      rect.x = border->left;
-      rect.y = border->top;
-      rect.width = allocation->width - border->left - border->right;
-      rect.height = allocation->height - border->top - border->bottom;
 
-      opaque_region = cairo_region_create_rectangle (&rect);
+  context = gtk_widget_get_style_context (GTK_WIDGET (window));
 
-      subtract_corners_from_region (opaque_region, &rect, context);
-    }
+  if (priv->tiled)
+    gtk_style_context_add_class (context, "tiled");
   else
-    {
-      opaque_region = NULL;
-    }
-
-  gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region);
+    gtk_style_context_remove_class (context, "tiled");
 
-  cairo_region_destroy (opaque_region);
+  if (priv->maximized)
+    gtk_style_context_add_class (context, "maximized");
+  else
+    gtk_style_context_remove_class (context, "maximized");
 }
 
 static void
@@ -7139,20 +7166,17 @@ _gtk_window_set_allocation (GtkWindow           *window,
 
   gtk_widget_set_allocation (widget, allocation);
 
-  get_shadow_width (widget, &window_border);
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
-
   child_allocation.x = 0;
   child_allocation.y = 0;
   child_allocation.width = allocation->width;
   child_allocation.height = allocation->height;
 
-  priv->title_height = 0;
+  get_shadow_width (widget, &window_border);
 
-  if (priv->client_decorated)
-    update_shadow_width (window, &window_border);
+  if (gtk_widget_get_realized (widget))
+    update_realized_window_properties (window, &child_allocation, &window_border);
 
-  update_opaque_region (window, &window_border, &child_allocation);
+  priv->title_height = 0;
 
   if (priv->title_box != NULL &&
       gtk_widget_get_visible (priv->title_box) &&
@@ -7188,23 +7212,14 @@ _gtk_window_set_allocation (GtkWindow           *window,
                                  priv->title_height;
     }
 
-  if (gtk_widget_get_realized (widget))
+  if (!gtk_widget_is_toplevel (widget) && gtk_widget_get_realized (widget))
     {
-      /* If it's not a toplevel we're embedded, we need to resize
-       * the window's window and skip the grip.
-       */
-      if (!gtk_widget_is_toplevel (widget))
-        {
-          gdk_window_move_resize (gtk_widget_get_window (widget),
-                                  allocation->x, allocation->y,
-                                  allocation->width, allocation->height);
-        }
-      else
-        {
-          update_border_windows (window);
-        }
+      gdk_window_move_resize (gtk_widget_get_window (widget),
+                              allocation->x, allocation->y,
+                              allocation->width, allocation->height);
     }
 
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
   child_allocation.x += border_width;
   child_allocation.y += border_width;
   child_allocation.width = MAX (1, child_allocation.width - border_width * 2);